package com.ruoyi.repn.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.ruoyi.common.config.WxPayConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.WXPayUtil;
import com.ruoyi.repn.domain.dto.RepOrderDto;
import com.ruoyi.repn.domain.params.WXPrePayParams;
import com.ruoyi.repn.domain.vo.WxPayNotifyVo;
import com.ruoyi.repn.domain.vo.WxPayRespVO;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import com.ruoyi.repn.mapper.RepOrderMapper;
import com.ruoyi.repn.domain.RepOrder;
import com.ruoyi.repn.service.IRepOrderService;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;

import static com.ruoyi.common.constant.ReportConstants.*;
import static com.ruoyi.common.constant.WXConstants.APP_ID;
import static com.ruoyi.common.constant.WXConstants.KEY_PATH;
import static com.wechat.pay.java.core.http.Constant.*;


/**
 * 年报订单Service业务层处理
 * 
 * @author cpf
 * @date 2024-03-02
 */
@Service
public class RepOrderServiceImpl implements IRepOrderService 
{
    @Autowired
    private RepOrderMapper repOrderMapper;

    @Autowired
    private WxPayConfig wxPayConfig;

    /**
     * 查询年报订单
     * 
     * @param id 年报订单主键
     * @return 年报订单
     */
    @Override
    public RepOrderDto selectRepOrderById(Long id)
    {
        return repOrderMapper.selectRepOrderById(id);
    }

    /**
     * 查询年报订单列表
     * 
     * @param repOrder 年报订单
     * @return 年报订单
     */
    @Override
    public List<RepOrderDto> selectRepOrderList(RepOrder repOrder)
    {
        List<RepOrderDto> repOrderDtos = repOrderMapper.selectRepOrderList(repOrder);
        for (RepOrderDto repOrderDto : repOrderDtos) {
            Date createTime = repOrderDto.getCreateTime();
            repOrderDto.setTime(createTime.getTime());
        }
        return repOrderDtos;
    }

    /**
     * 新增年报订单
     * 
     * @param repOrder 年报订单
     * @return 结果
     */
    @Override
    public AjaxResult insertRepOrder(RepOrder repOrder)
    {
        long timestamp = System.currentTimeMillis();
        repOrder.setOrderNo(""+timestamp);
        repOrder.setCreateTime(DateUtils.getNowDate());
        //未提交
        repOrder.setStatus(NOT_ENTERTAINED);
        //未支付
        repOrder.setPayStatus(NON_PAYMENT);
        int i = repOrderMapper.insertRepOrder(repOrder);
        if (i > 0){
            return AjaxResult.success(repOrder);
        }
        return AjaxResult.error();
    }

    /**
     * 修改年报订单
     * 
     * @param repOrder 年报订单
     * @return 结果
     */
    @Override
    public int updateRepOrder(RepOrder repOrder)
    {
        repOrder.setUpdateTime(DateUtils.getNowDate());
        return repOrderMapper.updateRepOrder(repOrder);
    }

    /**
     * 批量删除年报订单
     * 
     * @param ids 需要删除的年报订单主键
     * @return 结果
     */
    @Override
    public int deleteRepOrderByIds(Long[] ids)
    {
        return repOrderMapper.deleteRepOrderByIds(ids);
    }

    /**
     * 删除年报订单信息
     * 
     * @param id 年报订单主键
     * @return 结果
     */
    @Override
    public int deleteRepOrderById(Long id)
    {
        return repOrderMapper.deleteRepOrderById(id);
    }


    /**
     * 预支付
     * @param wxPrePayParams 预支付请求参数
     * @return  WxPayRespVO
     */
    @Override
    public WxPayRespVO prePay(WXPrePayParams wxPrePayParams) {
        String outTradeNo = wxPrePayParams.getOutTradeNo();
        BigDecimal totalPrice = wxPrePayParams.getTotalPrice();
        //检验订单信息
        verifyOrder(outTradeNo);

        //发起预支付请求
        PrepayResponse response = wxPayConfig.WxPay(outTradeNo, wxPrePayParams.getDescription(), totalPrice, wxPrePayParams.getOpenId());
        if (response == null){
            throw new RuntimeException("预支付信息异常！");
        }

        //构建返回信息
        WxPayRespVO vo = new WxPayRespVO();
        //prepay_id
        vo.setPrepayId("prepay_id=" + response.getPrepayId());
        //时间戳
        Long timeStamp = System.currentTimeMillis() / 1000;
        vo.setTimeStamp(timeStamp);
        //随机数
        String nonceStr = WXPayUtil.generateNonceStr();
        vo.setNonceStr(nonceStr);
        try {
            //生成签名
            String str = Stream.of(APP_ID, String.valueOf(timeStamp),nonceStr, "prepay_id=" + response.getPrepayId())
                    .collect(Collectors.joining("\n", "", "\n"));
            String sign = WXPayUtil.getSign(str, KEY_PATH);
            //签名
            vo.setPaySign(sign);
        } catch (Exception e) {
            throw new RuntimeException("签名生成失败");
        }
        return vo;
    }


    /**
     * 检验订单信息
     * @param outTradeNo 订单编号
     */
    private void verifyOrder(String outTradeNo) {
        RepOrder repOrder = repOrderMapper.selectRepOrderByOrderNo(outTradeNo);
        if (repOrder == null){
            throw new RuntimeException("订单异常！");
        }
    }


    /**
     *  支付回调
     *  回调接口需要暴露到公网上，且要放开token验证
     */
    @Override
    public ResponseEntity payNotify(HttpServletRequest request){

        //提前请求头信息
        WxPayNotifyVo vo = getWxPayNotifyVo(request);

        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(vo.getSerialNo())
                .nonce(vo.getNonce())
                .signature(vo.getSignature())
                .timestamp(vo.getTimestamp())
                .body(vo.getBody())
                .build();

        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(wxPayConfig.getMyRSAConfig());

        // 以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);

        System.out.println(transaction);

        /**
         * 111{"amount":{"currency":"CNY","payer_currency":"CNY","payer_total":1,"total":1},
         * "appid":"wx8939a70ec8708161",
         * "attach":"",
         * "bank_type":"OTHERS",
         * "mchid":"1666413915",
         * "out_trade_no":"333333",
         * "payer":{"openid":"oY9zG6whg88hvhkm_5A3JznTvPqk"},
         * "success_time":"2024-02-23T11:16:00+08:00",
         * "trade_state":"SUCCESS",
         * "trade_state_desc":"支付成功",
         * "trade_type":"JSAPI",
         * "transaction_id":"4200002056202402231071643098"}
         */

        //判断是否支付成功
        if(!transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)){
            // 支付失败
            return (ResponseEntity) ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
        }

        //订单编号
        String outTradeNo = transaction.getOutTradeNo();
        RepOrder repOrder = repOrderMapper.selectRepOrderByOrderNo(outTradeNo);
        if (repOrder == null){
            // 订单信息异常
            return (ResponseEntity) ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        //订单状态改为已付款
        repOrder.setPayStatus(HAVE_PAID);
        //受理中
        repOrder.setStatus(UNDER_CONSIDERATION);
        repOrderMapper.updateRepOrder(repOrder);


        // 处理成功，返回 200 OK 状态码
        return (ResponseEntity) ResponseEntity.status(HttpStatus.OK);

    }


    /**
     * 根据商户订单号查询订单是否支付成功
     * @param orderNo 商户订单号
     */
    @Override
    public AjaxResult isPay(String orderNo) {
        com.wechat.pay.java.service.payments.model.Transaction transaction = wxPayConfig.isPay(orderNo);
        if (transaction == null){
            // 支付失败
            return AjaxResult.error("订单编号为："+ orderNo +"的订单信息异常！");
        }
        if(!transaction.getTradeState().equals(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.SUCCESS)){
            // 支付失败
            return AjaxResult.error("订单编号为："+ orderNo +"的订单支付失败！");
        }

        RepOrder repOrder = repOrderMapper.selectRepOrderByOrderNo(orderNo);
        if (repOrder == null){
            // 支付失败
            return AjaxResult.error("订单编号为："+ orderNo +"的订单信息异常！");
        }
        //如果订单状态为已未支付，修改订单状态，如果为已支付，则不操作
        if (!repOrder.getPayStatus().equals(HAVE_PAID)){
            //订单状态改为已付款
            repOrder.setPayStatus(HAVE_PAID);
            //受理中
            repOrder.setStatus(UNDER_CONSIDERATION);
            repOrderMapper.updateRepOrder(repOrder);
        }
        return AjaxResult.success("订单编号为："+ orderNo +"的订单支付成功");
    }


    /**
     * 获取请求头信息
     */
    private static WxPayNotifyVo getWxPayNotifyVo(HttpServletRequest request){
        ServletInputStream inputStream;
        StringBuilder stringBuffer;
        try {
            inputStream = request.getInputStream();
            stringBuffer = new StringBuilder();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String s;
            //读取回调请求体
            while ((s = bufferedReader.readLine()) != null) {
                stringBuffer.append(s);
            }
        } catch (IOException e) {
            throw new RuntimeException("获取请求体信息失败");
        }
        WxPayNotifyVo vo = new WxPayNotifyVo();
        vo.setBody(stringBuffer.toString());
        vo.setTimestamp(request.getHeader(WECHAT_PAY_TIMESTAMP));
        vo.setNonce(request.getHeader(WECHAT_PAY_NONCE));
        vo.setSerialNo(request.getHeader(WECHAT_PAY_SERIAL));
        vo.setSignature(request.getHeader(WECHAT_PAY_SIGNATURE));
        return vo;
    }

}
